package com.huirui.server.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huirui.server.context.UserContext;
import com.huirui.server.mapper.ShippingCartMapper;
import com.huirui.server.pojo.dto.ShippingCartDto;
import com.huirui.server.pojo.dto.ShippingCartListDto;
import com.huirui.server.pojo.entity.ProductFavorite;
import com.huirui.server.pojo.entity.ProductSpecification;
import com.huirui.server.pojo.entity.ShippingCart;
import com.huirui.server.pojo.vo.ShippingCartVo;
import com.huirui.server.service.ProductFavoriteService;
import com.huirui.server.service.ProductSpecificationService;
import com.huirui.server.service.ShippingCartService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yujun
 * @description 针对表【t_shipping_cart(购物车表)】的数据库操作Service实现
 * @createDate 2025-09-21 14:36:59
 */
@Service
@Slf4j
public class ShippingCartServiceImpl extends ServiceImpl<ShippingCartMapper, ShippingCart>
        implements ShippingCartService {

    @Resource
    private ProductSpecificationService specificationService;

    @Resource
    private ProductFavoriteService productFavoriteService;

    @Override
    public void saveShippingCart(ShippingCartDto shippingCartDto) {
        Long userId = UserContext.getId();
        boolean exists = lambdaQuery()
                .eq(ShippingCart::getUserId, userId)
                .eq(ShippingCart::getProductSpecificationId, shippingCartDto.getProductSpecificationId())
                .exists();
        if (exists) {
            Integer quantity = lambdaQuery()
                    .select(ShippingCart::getQuantity)
                    .eq(ShippingCart::getUserId, userId)
                    .eq(ShippingCart::getProductSpecificationId, shippingCartDto.getProductSpecificationId())
                    .one()
                    .getQuantity();
            Double salePrice = specificationService
                    .lambdaQuery()
                    .select(ProductSpecification::getDiscountPrice)
                    .eq(ProductSpecification::getId, shippingCartDto.getProductSpecificationId())
                    .one()
                    .getDiscountPrice()
                    .doubleValue();
            lambdaUpdate()
                    .eq(ShippingCart::getUserId, userId)
                    .eq(ShippingCart::getProductSpecificationId, shippingCartDto.getProductSpecificationId())
                    .set(ShippingCart::getPrice, salePrice)
                    .set(ShippingCart::getQuantity, quantity + shippingCartDto.getQuantity())
                    .update();
            return;
        }
        ShippingCart shippingCart = new ShippingCart();
        Double salePrice = specificationService
                .lambdaQuery()
                .select(ProductSpecification::getDiscountPrice)
                .eq(ProductSpecification::getId, shippingCartDto.getProductSpecificationId())
                .one()
                .getDiscountPrice()
                .doubleValue();
        shippingCart.setPrice(salePrice);
        shippingCart.setProductSpecificationId(shippingCartDto.getProductSpecificationId());
        shippingCart.setQuantity(shippingCartDto.getQuantity());
        shippingCart.setUserId(userId);
        shippingCart.setProductId(shippingCartDto.getProductId());
        shippingCart.setCreatedTime(LocalDateTime.now());
        shippingCart.setUpdatedTime(LocalDateTime.now());
        save(shippingCart);
    }

    @Override
    public List<ShippingCartVo> listUserShippingCart() {
        Long userId = UserContext.getId();
        return baseMapper.selectShippingCartByUserId(userId);
    }

    @Override
    public void updateCartItemQuantity(Long id, Long newQuantity) {
        lambdaUpdate()
                .eq(ShippingCart::getUserId, UserContext.getId())
                .eq(ShippingCart::getId, id)
                .set(ShippingCart::getQuantity, newQuantity)
                .set(ShippingCart::getUpdatedTime, LocalDateTime.now())
                .update();
    }

    @Override
    public List<ShippingCartVo> listDiscountProducts() {
        Long userId = UserContext.getId();
        return baseMapper.listDiscountProducts(userId);
    }

    @Override
    public void removeShippingCartToFavorite(List<Long> ids) {
        List<Long> productIds = lambdaQuery()
                .select(ShippingCart::getProductId)
                .in(ShippingCart::getId, ids)
                .list()
                .stream()
                .map(ShippingCart::getProductId)
                .toList();
        // 删除已有的商品收藏
        productFavoriteService
                .lambdaUpdate()
                .eq(ProductFavorite::getUserId, UserContext.getId())
                .in(ProductFavorite::getProductId, productIds)
                .remove();
        // 生成新的商品收藏列表
        List<ProductFavorite> productFavoriteList = productIds.stream()
                .map(productId -> ProductFavorite
                        .builder()
                        .productId(productId)
                        .favoriteTime(LocalDateTime.now())
                        .userId(UserContext.getId())
                        .build()
                ).toList();
        // 删除购物车商品
        lambdaUpdate()
                .in(ShippingCart::getId, ids)
                .remove();
        // 插入商品收藏
        productFavoriteService.saveBatch(productFavoriteList);
    }

    @Override
    @Transactional
    public void batchSaveShippingCart(ShippingCartListDto shippingCartListDto) {
        List<ShippingCart> shippingCarts = new ArrayList<>();
        Long productId = shippingCartListDto.getProductId();
        Long userId = UserContext.getId();
        Set<Long> existsProductSpecificationIds = lambdaQuery()
                .eq(ShippingCart::getUserId, userId)
                .select(ShippingCart::getProductSpecificationId)
                .list()
                .stream()
                .map(ShippingCart::getProductSpecificationId)
                .collect(Collectors.toSet());
        shippingCartListDto.getShippingCartDtoList().forEach(shippingCartDto -> {
            Long productSpecificationId = shippingCartDto.getProductSpecificationId();
            // 查询该商品的价格
            BigDecimal price = specificationService
                    .lambdaQuery()
                    .eq(ProductSpecification::getId, productSpecificationId)
                    .select(ProductSpecification::getDiscountPrice)
                    .one().getDiscountPrice();

            if (existsProductSpecificationIds.contains(productSpecificationId)) {
                // 已存在该购物车项，新增数量
                lambdaUpdate()
                        .eq(ShippingCart::getProductSpecificationId, productSpecificationId)
                        .eq(ShippingCart::getUserId, userId)
                        .setIncrBy(ShippingCart::getQuantity, shippingCartDto.getQuantity())
                        .set(ShippingCart::getPrice, price)
                        .update();
            } else {
                // 新增该购物车项
                ShippingCart shippingCart = new ShippingCart();
                shippingCart.setProductSpecificationId(productSpecificationId);
                shippingCart.setUserId(userId);
                shippingCart.setProductId(productId);
                shippingCart.setCreatedTime(LocalDateTime.now());
                shippingCart.setUpdatedTime(LocalDateTime.now());
                shippingCart.setQuantity(Math.toIntExact(shippingCartDto.getQuantity()));
                shippingCart.setPrice(price.doubleValue());
                shippingCarts.add(shippingCart);
            }
        });
        if (!shippingCarts.isEmpty()) {
            saveBatch(shippingCarts);
        }
    }

    @Override
    public Long countShippingCart() {
        return lambdaQuery()
                .eq(ShippingCart::getUserId, UserContext.getId())
                .count();
    }


}




